﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using System.Linq;

//------------------------------------------------------------
// shaco Framework
// Copyright © 2017-2021 chang.liu All rights reserved.
// Feedback: 449612236@qq.com
//------------------------------------------------------------

namespace shacoEditor
{
    public class PrefabHelper
    {
        static public void RemoveAllUnusedOverride(GameObject prefab, bool includeInactive)
        {
            var prefabs = GetAllPrefabInstance(prefab, includeInactive);
            RemovePrefabInstanceUnusedOverrides(prefabs.ToArray());
        }

        static public System.Array GetPrefabInstanceOverridesInfos(GameObject[] prefabs)
        {
            var methodGetPrefabInstancesOverridesInfos = typeof(PrefabUtility).GetMethod("GetPrefabInstancesOverridesInfos", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
            var unusedOverrideInfo = methodGetPrefabInstancesOverridesInfos.Invoke(null, new object[] { prefabs });
            return unusedOverrideInfo as System.Array;
        }

        static public GameObject GetPrefabInstanceFromOverridesInfo(object overrideInfo)
        {
            var overrideInfoTypeName = "UnityEditor.PrefabUtility+InstanceOverridesInfo";
            if (overrideInfo.GetType().FullName != overrideInfoTypeName)
            {
                Debug.LogError($"GetPrefabInstanceFromOverridesInfo error: not type {overrideInfoTypeName}");
                return null;
            }

            return overrideInfo.GetType().GetProperty("instance", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance).GetValue(overrideInfo) as GameObject;
        }

        static public bool HasPrefabInstanceUnusedOverrides_CachedForUI(GameObject prefab)
        {
            var method = typeof(PrefabUtility).GetMethod("HasPrefabInstanceUnusedOverrides_CachedForUI", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic, null,
                                                                                            new System.Type[] { prefab.GetType() }, null);
            return (bool)method.Invoke(null, new object[] { prefab });
        }

        static public bool RemovePrefabInstanceUnusedOverrides(object overrideInfo)
        {
            var overrideInfoTypeName = "UnityEditor.PrefabUtility+InstanceOverridesInfo";
            if (overrideInfo.GetType().FullName != overrideInfoTypeName)
            {
                Debug.LogError($"RemovePrefabInstanceUnusedOverrides error: not type {overrideInfoTypeName}");
                return false;
            }

            var typeInstanceOverridesInfo = System.Type.GetType("UnityEditor.PrefabUtility+InstanceOverridesInfo, UnityEditor");
            var methodRemovePrefabInstanceUnusedOverrides = typeof(PrefabUtility).GetMethod("RemovePrefabInstanceUnusedOverrides", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic, null,
                                                                                            new System.Type[] { typeInstanceOverridesInfo }, null);
            return (bool)methodRemovePrefabInstanceUnusedOverrides.Invoke(null, new object[] { overrideInfo });
        }

        static public bool RemovePrefabInstanceUnusedOverrides(GameObject prefab)
        {
            var typeInstanceOverridesInfo = System.Type.GetType("UnityEditor.PrefabUtility+InstanceOverridesInfo, UnityEditor");
            var methodRemovePrefabInstanceUnusedOverrides = typeof(PrefabUtility).GetMethod("RemovePrefabInstanceUnusedOverrides", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic, null,
                                                                                            new System.Type[] { typeInstanceOverridesInfo }, null);
            var unusedOverrideInfo = GetPrefabInstanceOverridesInfo(prefab);
            if (null != unusedOverrideInfo)
            {
                return (bool)methodRemovePrefabInstanceUnusedOverrides.Invoke(null, new object[] { unusedOverrideInfo });
            }
            return false;
        }

        static public bool RemovePrefabInstanceUnusedOverrides(GameObject[] prefabs)
        {
            var typeInstanceOverridesInfo = System.Type.GetType("UnityEditor.PrefabUtility+InstanceOverridesInfo[], UnityEditor");
            var methodRemovePrefabInstanceUnusedOverrides = typeof(PrefabUtility).GetMethod("RemovePrefabInstanceUnusedOverrides", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic, null,
                                                                                            new System.Type[] { typeInstanceOverridesInfo }, null);
            var unusedOverrideInfo = GetPrefabInstanceOverridesInfos(prefabs);
            if ((unusedOverrideInfo as System.Array).Length > 0)
            {
                methodRemovePrefabInstanceUnusedOverrides.Invoke(null, new object[] { unusedOverrideInfo });
                return true;
            }
            return false;
        }

        static bool IsPrefab(GameObject gameObject)
        {
            var assetType = PrefabUtility.GetPrefabAssetType(gameObject);
            var prefabType = PrefabUtility.GetPrefabInstanceStatus(gameObject);

            var retValue = (assetType == PrefabAssetType.Regular || assetType == PrefabAssetType.Variant) && prefabType != PrefabInstanceStatus.NotAPrefab;
            return retValue;
        }

        static IEnumerable<GameObject> GetAllPrefabInstance(GameObject prefab, bool includeInactive)
        {
            return prefab.GetChildren(includeInactive).Where(v => IsPrefab(v.gameObject)).Select(v => v.gameObject);
        }

        static object GetPrefabInstanceOverridesInfo(GameObject prefab)
        {
            var methodGetPrefabInstancesOverridesInfos = typeof(PrefabUtility).GetMethod("GetPrefabInstanceOverridesInfo", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
            var unusedOverrideInfo = methodGetPrefabInstancesOverridesInfos.Invoke(null, new object[] { prefab });
            return unusedOverrideInfo as System.Array;
        }
    }
}